UNICEF Global Youth Mortality Report

---
title: "UNICEF Global Youth Mortality Report"
format:
  html:
    embed-resources: true
    code-fold: true
    theme: cosmo
    css: styles.css
execute:
  enabled: true
jupyter: python3
---
Code
from IPython.display import display, HTML

display(HTML("""
<style>
.container { width: '100%',
transition: 'concave'}
</style>
"""))
Code
import pandas as pd
from plotnine import *
from mizani.formatters import comma_format
import plotly.express as px

# Load your data
df = pd.read_csv("unicef_indicator_1.csv")
meta = pd.read_csv("unicef_metadata.csv")

# Filter latest year + relevant indicator
latest_year = df['time_period'].max()
df_deaths_world = df[
    (df['indicator'] == 'Deaths aged 5 to 24') &
    (df['time_period'] == latest_year) &
    (df['sex'] == 'Total')
]

# Merge with metadata
df_map = df_deaths_world.merge(meta[['country', 'alpha_3_code']], on='country', how='left')
df_map.rename(columns={"alpha_3_code_y": "alpha_3_code"}, inplace=True)
df_map.drop(columns=["alpha_3_code_x"], errors="ignore", inplace=True)
df_map['obs_value'] = pd.to_numeric(df_map['obs_value'], errors='coerce')

# Create choropleth map
world_map = px.choropleth(
    df_map,
    locations='alpha_3_code',
    color='obs_value',
    hover_name='country',
    color_continuous_scale='Blues',
    projection='natural earth',
    labels={
        'alpha_3_code': 'Country_Code',
        'obs_value': 'Total Death'
    }
)

world_map.update_layout(
    autosize=True,
    margin=dict(t=40, l=0, r=0, b=0),
    dragmode=False,  
    geo=dict(
        projection_type='natural earth',
        showcoastlines=True,
        showframe=False,
        showcountries=True,
        fitbounds="locations",     
        projection_scale=1,        
        center=dict(lat=0, lon=0)
    )
    
)
# Convert charts to HTML
map_html = world_map.to_html(include_plotlyjs='cdn', full_html=False)

# Display with full-width stacked layout
display(HTML(f"""
<style>
body {{
  margin: 0;
  font-family: Arial, sans-serif;
  background-color: #c1d0d4
}}

.dashboard-vertical {{
  flex-direction: column;
  gap: 10px;
  padding: 20px;
  max-width: 100%;
  box-sizing: border-box;
}}

.chart-box {{
  background-color: #5883a6;
  border: 2px solid #5883a6;
  padding: 15px;
  text-align: center;
}}

.h2,.p{{
font-family: Arial, sans-serif;
color: white;
}}
</style>

<div class="dashboard-vertical">
  <div class="chart-box">
    <h2 class="h2">Youth Mortality by Country (Ages 5–24) – 2022</h2>
             <p class="p">Displays global distribution of youth deaths by country of latest year</p>
    {map_html}
  </div>
</div>
"""))

Youth Mortality by Country (Ages 5–24) – 2022

Displays global distribution of youth deaths by country of latest year

Code
# ─────────────────────────────────────────────
# 2. Bar Chart (Top 10 countries with highest deaths)
# ─────────────────────────────────────────────

# Calculate total deaths across all years

df_deaths_bar = df[df['indicator'] == 'Deaths aged 5 to 24']
df_deaths_bar= df_deaths_bar[df_deaths_bar['sex'] == 'Total']
top10_total_deaths = (
    df_deaths_bar.groupby('country')['obs_value']
    .sum()
    .sort_values(ascending=False)
    .head(10)
    .reset_index()
)
top10_total_deaths = top10_total_deaths.merge(
    df_deaths_bar[['country', 'alpha_3_code']].drop_duplicates(),
    on='country',
    how='left'
)
top10_total_deaths["obs_value_millions"] = top10_total_deaths["obs_value"] / 1e6
top10_sorted = top10_total_deaths.sort_values(by='alpha_3_code')

# Plot the chart
bar_chart_plotly = px.bar(
    top10_sorted,
    x='alpha_3_code',
    y='obs_value_millions',
    text=top10_sorted["obs_value_millions"].round(1),
    color='country',
    labels={
        'alpha_3_code': 'Country_Code',
        'obs_value_millions': 'Total Deaths (in Millions)'
    },
    template='plotly_white'
)

bar_chart_plotly.update_traces(
    textposition='outside',
    marker=dict(line=dict(color='grey', width=1))
)

bar_chart_plotly.update_layout(
    yaxis=dict(title='Total Deaths (in Millions)'),
    xaxis=dict(title='Country', categoryorder='array', categoryarray=top10_sorted['alpha_3_code']),
    margin=dict(t=50, b=50),
   # width=700,
    #height=400
)
bar_html = bar_chart_plotly.to_html(include_plotlyjs=False, full_html=False)

# Display with full-width stacked layout
display(HTML(f"""
<div class="dashboard-vertical">
  <div class="chart-box">
    <h2 class="h2">Top 10 Countries by Total Death Rate</h2>
             <p class="p">Highlights countries with the highest total youth deaths of all time</p>
    {bar_html}
  </div>
</div>
"""))

Top 10 Countries by Total Death Rate

Highlights countries with the highest total youth deaths of all time

Code
# ─────────────────────────────────────────────
# 3. Scatterplot + Regression (Deaths vs GDP per Capita)
# ─────────────────────────────────────────────

# STEP 1: Get Top 10 Countries by Population

meta_clean = meta.dropna(subset=['Population'])
meta_clean = meta_clean.drop_duplicates(subset='country', keep='first')
meta_top10 = meta_clean.sort_values(by='Population', ascending=False).head(10)

# STEP 2: Filter death data for 'Total' (all years)
df_deaths_total_scatter = df[
    (df['indicator'] == 'Deaths aged 5 to 24') &
    (df['sex'] == 'Total') &
    (df['country'].isin(meta_top10['country']))
]

# STEP 3: Sum total deaths across all years
df_deaths_sum = df_deaths_total_scatter.groupby('country', as_index=False)['obs_value'].sum()
df_deaths_sum.rename(columns={'obs_value': 'total_deaths'}, inplace=True)

# STEP 4: Merge with population
df_scatter = df_deaths_sum.merge(meta_top10[['country', 'Population']], on='country', how='left')

# STEP 5: Convert to millions and clean
df_scatter['Population_M'] = pd.to_numeric(df_scatter['Population'], errors='coerce') / 1e6
df_scatter['Deaths_M'] = pd.to_numeric(df_scatter['total_deaths'], errors='coerce') / 1e6
df_scatter = df_scatter.dropna()

# STEP 6: Plot with Regression Line
scatter_plot = px.scatter(
    df_scatter,
    x='Population_M',
    y='Deaths_M',
    color='country',
    hover_name='country',
    trendline='ols',  # Adds regression line
    hover_data={
        'Population_M': ':.2f',
        'Deaths_M': ':.2f'
    },
    labels={
        'Population_M': 'Population (Millions)',
        'Deaths_M': 'Total Deaths (Millions)',
        'country': 'Country'
    },
    template='simple_white'
)
scatter_plot.update_traces(marker=dict(size=15))

scatter_html = scatter_plot.to_html(include_plotlyjs=False, full_html=False)

# Display with full-width stacked layout
display(HTML(f"""
<div class="dashboard-vertical">
  <div class="chart-box">
    <h2 class="h2">Deaths vs Birth</h2>
             <p class="p">Top 10 Death vs Birth comparison of all the time</p>
    {scatter_html}
  </div>
</div>
"""))

Deaths vs Birth

Top 10 Death vs Birth comparison of all the time

Code
# ─────────────────────────────────────────────
# 4. Time Series Chart (global average over years)
# ─────────────────────────────────────────────
df_deaths_time_series = df[
    (df['indicator'] == 'Deaths aged 5 to 24') &
    (df['sex'] == 'Total')
][['country', 'time_period', 'obs_value']].copy()
df_deaths_time_series.rename(columns={'obs_value': 'death_rate'}, inplace=True)

# STEP 2: Get Birth Rate from meta
df_births = meta[['country', 'time_period', 'birth_rate']].dropna().copy()

# STEP 3: Merge both on country + year
df_combined = pd.merge(df_deaths_time_series, df_births, on=['country', 'time_period'], how='inner')

# STEP 4: Group each separately by year
df_birth_yearly = df_combined.groupby('time_period', as_index=False)['birth_rate'].mean()
df_death_yearly = df_combined.groupby('time_period', as_index=False)['death_rate'].mean()
df_death_yearly['death_rate'] = df_death_yearly['death_rate'] / 1e3  # convert to Thousands

birth_hover = px.line(
    df_birth_yearly,
    x='time_period',
    y='birth_rate',
    markers=True,
    labels={
        'time_period': 'Year',
        'birth_rate': 'Births per 1,000 People'
    },
    template='simple_white'
)

birth_hover.update_traces(
    hovertemplate='Year: %{x}<br>Birth Rate: %{y:.2f}',
    line=dict(color='green'),
    marker=dict(color='black', size=8)
)
death_hover = px.line(
    df_death_yearly,
    x='time_period',
    y='death_rate',
    markers=True,
    labels={
        'time_period': 'Year',
        'death_rate': 'Deaths (in Thousands)'
    },
    template='simple_white',
   # width=700,
   # height=400
)
death_hover.update_traces(
    hovertemplate='Year: %{x}<br>Deaths: %{y:.2f}K',
    line=dict(color='crimson'),
    marker=dict(color='black', size=8)
)

death_html = death_hover.to_html(include_plotlyjs=False, full_html=False)
# Display with full-width stacked layout
display(HTML(f"""
<div class="dashboard-vertical">
  <div class="chart-box">
    <h2 class="h2">Global Youth Death Rate </h2>
             <p class="p">Shows how youth death rates have changed year by year across all the countries</p>
    {death_html}
  </div>
</div>
"""))

birth_html = birth_hover.to_html(include_plotlyjs=False, full_html=False)
# Display with full-width stacked layout
display(HTML(f"""
<div class="dashboard-vertical">
  <div class="chart-box">
    <h2 class="h2">Global Youth Birth Rate </h2>
             <p class="p">Shows how youth birth rates have changed year by year across all the countries</p>
    {birth_html}
  </div>
</div>
"""))

Global Youth Death Rate

Shows how youth death rates have changed year by year across all the countries

Global Youth Birth Rate

Shows how youth birth rates have changed year by year across all the countries